﻿using eLearning.WebServices;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Net;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Browser.Net;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace AgLux
{
    /// <summary>
    /// Represents a component that displays controllable media.
    /// </summary>

    public class Media : Component
    {
        protected MediaElement _media;
        protected Canvas _panelArea, _mediaPanel;
        protected ScaleTransform _mediaPanelScale;

        protected Canvas _scrub;
        protected Shape _scrubBar, _scrubber;
        protected Canvas _rewind, _stop, _play, _pause, _forward;
        protected TextBlock _pastTime, _totalTime;
        
        protected Canvas _enterMediaFullScreen, _leaveMediaFullScreen;
        protected Canvas _showTranscript;
        protected GradientStop _showTranscriptColor1, _showTranscriptColor2, _showTranscriptColor3;

        protected List<Shape> _volumes;
        protected Canvas _mute, _higherVolume, _lowerVolume;
        protected MediaElement _volumeSound;

        protected Storyboard _second, _millisecond, _mediaPanelScaleUp, _mediaPanelScaleDown, _speakerOn, _speakerOff, _speakerBlink;
        protected SplineDoubleKeyFrame _mediaPanelScaleUpX, _mediaPanelScaleUpY, _mediaPanelScaleDownX, _mediaPanelScaleDownY;

        protected MouseEventHandler _showTranscriptPressHandler;
        protected string _transcript;
        protected double _filling, _totalMilliseconds;
        protected bool _isShowingPanel, _isFocusingPanel, _isScrubbing;

        /// <summary>
        /// Initializes a new instance of the Media class.
        /// </summary>

        /// <param name="source">
        /// The media source.
        /// </param>

        /// <param name="caption">
        /// The media caption.
        /// </param>

        /// <param name="transcript">
        /// The media transcript source.
        /// </param>

        protected Media(string source, string caption, string transcript, double filling)
            : base()
        {
            _media = (MediaElement)_resource.FindName("media");
            _panelArea = (Canvas)_resource.FindName("panelArea");
            _mediaPanel = (Canvas)_resource.FindName("mediaPanel");
            _mediaPanelScale = (ScaleTransform)_resource.FindName("mediaPanelScale");

            _scrub = (Canvas)_resource.FindName("scrub");
            _scrubBar = (Shape)_resource.FindName("scrubBar");
            _scrubber = (Shape)_resource.FindName("scrubber");

            _rewind = (Canvas)_resource.FindName("rewind");
            _stop = (Canvas)_resource.FindName("stop");
            _play = (Canvas)_resource.FindName("play");
            _pause = (Canvas)_resource.FindName("pause");
            _forward = (Canvas)_resource.FindName("forward");

            _pastTime = (TextBlock)_resource.FindName("pastTime");
            _totalTime = (TextBlock)_resource.FindName("totalTime");

            _enterMediaFullScreen = (Canvas)_resource.FindName("enterMediaFullScreen");
            _leaveMediaFullScreen = (Canvas)_resource.FindName("leaveMediaFullScreen");
            _showTranscript = (Canvas)_resource.FindName("showTranscript");

            _showTranscriptColor1 = (GradientStop)_resource.FindName("showTranscriptColor1");
            _showTranscriptColor2 = (GradientStop)_resource.FindName("showTranscriptColor2");
            _showTranscriptColor3 = (GradientStop)_resource.FindName("showTranscriptColor3");
            
            _volumes = new List<Shape>();
            _volumes.Add((Shape)_resource.FindName("volume1"));
            _volumes.Add((Shape)_resource.FindName("volume2"));
            _volumes.Add((Shape)_resource.FindName("volume3"));
            _volumes.Add((Shape)_resource.FindName("volume4"));
            _volumes.Add((Shape)_resource.FindName("volume5"));
            _volumes.Add((Shape)_resource.FindName("volume6"));
            _volumes.Add((Shape)_resource.FindName("volume7"));
            _volumes.Add((Shape)_resource.FindName("volume8"));
            _volumes.Add((Shape)_resource.FindName("volume9"));
            _volumes.Add((Shape)_resource.FindName("volume10"));

            _mute = (Canvas)_resource.FindName("mute");
            _higherVolume = (Canvas)_resource.FindName("higherVolume");
            _lowerVolume = (Canvas)_resource.FindName("lowerVolume");
            _volumeSound = (MediaElement)_resource.FindName("volumeSound");

            _second = (Storyboard)_resource.FindName("second");
            _millisecond = (Storyboard)_resource.FindName("millisecond");
            _mediaPanelScaleUp = (Storyboard)_resource.FindName("mediaPanelScaleUp");
            _mediaPanelScaleDown = (Storyboard)_resource.FindName("mediaPanelScaleDown");

            _speakerOn = (Storyboard)_resource.FindName("speakerOn");
            _speakerOff = (Storyboard)_resource.FindName("speakerOff");
            _speakerBlink = (Storyboard)_resource.FindName("speakerBlink");

            _mediaPanelScaleUpX = (SplineDoubleKeyFrame)_resource.FindName("mediaPanelScaleUpX");
            _mediaPanelScaleUpY = (SplineDoubleKeyFrame)_resource.FindName("mediaPanelScaleUpY");
            _mediaPanelScaleDownX = (SplineDoubleKeyFrame)_resource.FindName("mediaPanelScaleDownX");
            _mediaPanelScaleDownY = (SplineDoubleKeyFrame)_resource.FindName("mediaPanelScaleDownY");

            _showTranscriptPressHandler = new MouseEventHandler(ShowTranscript);
            _transcript = transcript;
            _filling = filling;
            _totalMilliseconds = 0;
            _isShowingPanel = _isFocusingPanel = _isScrubbing = false;

            _screen.Background = new SolidColorBrush(Colors.Black);
            _media.Source = new Uri(source, UriKind.RelativeOrAbsolute);
            _media.MediaOpened += new EventHandler(SetTotalTime);
            _media.MediaEnded += new EventHandler(Stop);

            _mediaPanel.MouseMove += new MouseEventHandler(CheckScrubbing);
            _mediaPanel.MouseLeftButtonUp += new MouseEventHandler(InactivateScrubbing);
            _mediaPanel.MouseLeave += new EventHandler(InactivateScrubbing);
            _scrub.MouseLeftButtonDown += new MouseEventHandler(ActivateScrubbing);

            _rewind.MouseLeftButtonDown += new MouseEventHandler(Rewind);
            _stop.MouseLeftButtonDown += new MouseEventHandler(Stop);
            _play.MouseLeftButtonDown += new MouseEventHandler(Play);
            _pause.MouseLeftButtonDown += new MouseEventHandler(Pause);
            _forward.MouseLeftButtonDown += new MouseEventHandler(Forward);

            if (_transcript == null)
            {
                _showTranscriptColor1.Color = _showTranscriptColor2.Color = _showTranscriptColor3.Color = Colors.Black;
            }
            else
            {
                _showTranscript.MouseLeftButtonDown += _showTranscriptPressHandler;
            }

            _mute.MouseLeftButtonDown += new MouseEventHandler(Mute);
            _higherVolume.MouseLeftButtonDown += new MouseEventHandler(HigherVolume);
            _lowerVolume.MouseLeftButtonDown += new MouseEventHandler(LowerVolume);

            _millisecond.Completed += new EventHandler(MoveScrubber);
            _caption.Text = caption;
        }

        /// <summary>
        /// Ends the activity of the component.
        /// </summary>

        public override void End()
        {
            base.End();
            Stop(_stop, new EventArgs());
        }

        /// <summary>
        /// Scrubs the media.
        /// </summary>

        /// <param name="xCoordinate">
        /// The X coordinate which to scrub the media.
        /// </param>

        protected virtual void Scrub(double xCoordinate)
        {
            if (xCoordinate < 0)
            {
                xCoordinate = 0;
            }
            else if (xCoordinate > _scrubBar.Width)
            {
                xCoordinate = _scrubBar.Width;
            }

            _media.Position = new TimeSpan(0, 0, 0, 0, (int)(xCoordinate * _totalMilliseconds / _scrubBar.Width));
            _scrubber.SetValue(Canvas.LeftProperty, xCoordinate + 25);
            _pastTime.Text = FormatNumber(_media.Position.Hours) + ":" + FormatNumber(_media.Position.Minutes) + ":" + FormatNumber(_media.Position.Seconds);
        }

        /// <summary>
        /// Formats a specific number to at least two figures.
        /// </summary>

        /// <param name="number">
        /// The number to be formatted.
        /// </param>

        /// <returns>
        /// The formatted number as a string.
        /// </returns>

        protected virtual string FormatNumber(int number)
        {
            string formattedNumber = Convert.ToString(number);
            if (formattedNumber.Length < 2)
            {
                formattedNumber = "0" + formattedNumber;
            }
            return formattedNumber;
        }

        /// <summary>
        /// Occurs when the media is opened.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The EventArgs that contains the event data.
        /// </param>

        protected virtual void SetTotalTime(object sender, EventArgs args)
        {
            _totalTime.Text = FormatNumber(_media.NaturalDuration.TimeSpan.Hours) + ":" + FormatNumber(_media.NaturalDuration.TimeSpan.Minutes) + ":" + FormatNumber(_media.NaturalDuration.TimeSpan.Seconds);
            _totalMilliseconds = Convert.ToDouble(_media.NaturalDuration.TimeSpan.TotalMilliseconds);
        }

        /// <summary>
        /// Occurs when the rewind button is pressed.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The MouseEventArgs that contains the event data.
        /// </param>

        protected virtual void Rewind(object sender, MouseEventArgs args)
        {
            //
        }

        /// <summary>
        /// Occurs when the stop button is pressed.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The EventArgs that contains the event data.
        /// </param>

        protected virtual void Stop(object sender, EventArgs args)
        {
            _media.Stop();
            _millisecond.Stop();

            Scrub(0);
            _pause.Visibility = Visibility.Collapsed;
            _play.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// Occurs when the play button is pressed.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The MouseEventArgs that contains the event data.
        /// </param>

        protected virtual void Play(object sender, MouseEventArgs args)
        {
            _media.Play();
            _millisecond.Begin();

            _play.Visibility = Visibility.Collapsed;
            _pause.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// Occurs when the pause button is pressed.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The MouseEventArgs that contains the event data.
        /// </param>

        protected virtual void Pause(object sender, MouseEventArgs args)
        {
            _media.Pause();
            _millisecond.Stop();

            _pause.Visibility = Visibility.Collapsed;
            _play.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// Occurs when the forward button is pressed.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The MouseEventArgs that contains the event data.
        /// </param>

        protected virtual void Forward(object sender, MouseEventArgs args)
        {
            //
        }

        /// <summary>
        /// Occurs when the show transcript button is pressed.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The MouseEventArgs that contains the event data.
        /// </param>

        protected virtual void ShowTranscript(object sender, MouseEventArgs args)
        {
            Service service = new Service();
            HtmlPage.Navigate(service.CreateTranscript(_transcript), "");
            service.DeleteTranscript();
        }

        /// <summary>
        /// Occurs when the mute button is pressed.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The MouseEventArgs that contains the event data.
        /// </param>

        protected virtual void Mute(object sender, MouseEventArgs args)
        {
            if (_media.IsMuted)
            {
                _media.IsMuted = false;
                _speakerOn.Begin();
            }
            else
            {
                _media.IsMuted = true;
                _speakerOff.Begin();
            }
        }

        /// <summary>
        /// Occurs when the higher volume button is pressed.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The EventArgs that contains the event data.
        /// </param>

        protected virtual void HigherVolume(object sender, EventArgs args)
        {
            _media.Volume += 0.1;
            _volumes[Convert.ToInt32(_media.Volume * 10) - 1].SetValue(Shape.FillProperty, "#FF00FF00");

            _volumeSound.Stop();
            _volumeSound.Volume += 0.1;
            _volumeSound.Play();
            _speakerBlink.Begin();

        }

        /// <summary>
        /// Occurs when the lower volume button is pressed.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The EventArgs that contains the event data.
        /// </param>

        protected virtual void LowerVolume(object sender, EventArgs args)
        {
            _media.Volume -= 0.1;
            _volumes[Convert.ToInt32(_media.Volume * 10)].SetValue(Shape.FillProperty, "#FF969696");

            _volumeSound.Stop();
            _volumeSound.Volume -= 0.1;
            _volumeSound.Play();
            _speakerBlink.Begin();
        }

        /// <summary>
        /// Occurs when the mouse pointer is moving over the control panel.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The MouseEventArgs that contains the event data.
        /// </param>

        protected virtual void CheckScrubbing(object sender, MouseEventArgs args)
        {
            if (_isScrubbing)
            {
                Scrub(args.GetPosition(_scrubBar).X - _scrubber.Width / 2);
            }
        }

        /// <summary>
        /// Occurs when is is time to inactivate scrolling.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The EventArgs that contains the event data.
        /// </param>

        protected virtual void InactivateScrubbing(object sender, EventArgs args)
        {
            _isScrubbing = false;
            if (_pause.Visibility == Visibility.Visible)
            {
                _media.Play();
                _millisecond.Begin();
            }
        }

        /// <summary>
        /// Occurs when is is time to activate scrolling.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The MouseEventArgs that contains the event data.
        /// </param>

        protected virtual void ActivateScrubbing(object sender, MouseEventArgs args)
        {
            _isScrubbing = true;
            if (_pause.Visibility == Visibility.Visible)
            {
                _media.Pause();
                _millisecond.Stop();
            }
            CheckScrubbing(sender, args);
        }

        /// <summary>
        /// Occurs when it is time for the scrubber to move.
        /// </summary>

        /// <param name="sender">
        /// The object that raised the event.
        /// </param>

        /// <param name="args">
        /// The EventArgs that contains the event data.

        protected virtual void MoveScrubber(object sender, EventArgs args)
        {
            _scrubber.SetValue(Canvas.LeftProperty, (Convert.ToDouble(_media.Position.TotalMilliseconds) / _totalMilliseconds * _scrubBar.Width) + 25);
            _pastTime.Text = FormatNumber(_media.Position.Hours) + ":" + FormatNumber(_media.Position.Minutes) + ":" + FormatNumber(_media.Position.Seconds);
            _millisecond.Begin();
        }
    }
}
